
library ieee;
 use ieee.std_logic_1164.all;
 use ieee.std_logic_unsigned.all;
 use ieee.std_logic_arith.all;
 use ieee.math_real.all; 
 use ieee.numeric_std.all;
 
library work;
    use work.router_pack.all;
    use work.env_pack.all;
    use work.env_functions.all;

-------------------------------------------------------------------------
    
entity injector_packet_gen is

port(
    -- General Signals: --
    RESET           		: in std_logic;
    CLK             		: in std_logic;
    MODULE_ID		       : in std_logic_vector(2*e_coord_position_width_c-1 downto 0);
    
    -- Packet Info: --
    PACKET_REQ		      : out std_logic;
    SL              		: out std_logic_vector(msl_ind_width-1 downto 0);
    VC              		: out std_logic_vector(vc_width-1 downto 0);
    SOURCE_ROUTING  	 : out std_logic_vector(e_flit_data_width_c-1 downto 0);
    PACKET_SIZE     	 : out std_logic_vector(e_packet_size_width_c-1 downto 0);
    PACKET_ID       	 : out std_logic_vector(e_packet_id_width_c-1 downto 0);
    PACKET_SENT      	: in  std_logic;
    
    -- Environment Settings --
    WORKLOAD          : in std_logic_vector(e_workload_width_c-1 downto 0);
    MAX_VC            : in std_logic_vector(vc_width-1 downto 0);
    MAX_SL            : in std_logic_vector(msl_ind_width-1 downto 0);
    MAX_PACKET_SIZE   : in std_logic_vector(e_packet_size_width_c-1 downto 0);
    MIN_PACKET_SIZE   : in std_logic_vector(e_packet_size_width_c-1 downto 0);
    SEED1             : in std_logic_vector(e_seed_width_c-1 downto 0);
    SEED2             : in std_logic_vector(e_seed_width_c-1 downto 0)
);
    
end injector_packet_gen;

-------------------------------------------------------------------------

architecture injector_packet_gen_arch of injector_packet_gen is

	signal packet_counter	: std_logic_vector(e_packet_counter_width_c-1 downto 0) := conv_std_logic_vector(0, e_packet_counter_width_c);
	signal rand_sl		: std_logic_vector(msl_ind_width-1 downto 0);
	signal rand_vc		: std_logic_vector(vc_width-1 downto 0);
	signal rand_routing	: std_logic_vector(e_flit_data_width_c-1 downto 0);
	signal rand_size		: std_logic_vector(e_packet_size_width_c-1 downto 0);
	signal local_x_coord	: std_logic_vector(e_coord_position_width_c-1 downto 0);
	signal local_y_coord	: std_logic_vector(e_coord_position_width_c-1 downto 0);
--	signal dest_x_coord	: std_logic_vector(e_coord_position_width_c-1 downto 0);
--	signal dest_y_coord	: std_logic_vector(e_coord_position_width_c-1 downto 0);
	
	signal wait_time : std_logic_vector(inj_wait_max_width_c-1 downto 0);
   	signal wait_time_counter : std_logic_vector(inj_wait_max_width_c-1 downto 0) := conv_std_logic_vector(0, inj_wait_max_width_c);
   	signal packet_tx_counter : std_logic_vector(inj_wait_max_width_c-1 downto 0);
   	signal in_wait_mode : std_logic;  
   	signal prev_reset : std_logic;
   	signal seed_1 : integer;
   	signal seed_2 : integer;
   	
   
begin    
   gen_packet: process(RESET, CLK, PACKET_SENT, WORKLOAD)
   variable randNum  : real;
   variable dest_x_coord : std_logic_vector(e_coord_position_width_c-1 downto 0);
   variable dest_y_coord : std_logic_vector(e_coord_position_width_c-1 downto 0);
   variable wait_time_counter_next : std_logic_vector(inj_wait_max_width_c-1 downto 0);
   variable packet_counter_next : std_logic_vector(e_packet_counter_width_c-1 downto 0);
   variable seed1_v : integer;
   variable seed2_v : integer;
   variable in_tx : std_logic;
   variable sl_var :std_logic_vector(msl_ind_width-1 downto 0);
	begin
		if (CLK'event and (CLK = '1')) then
		
			seed1_v := seed_1;
	   		seed2_v := seed_2;
		
			if (RESET = '1') then
				packet_counter_next := conv_std_logic_vector(0, e_packet_counter_width_c);		
				wait_time_counter_next := conv_std_logic_vector(0, inj_wait_max_width_c);	
				local_x_coord	    <= MODULE_ID(2*e_coord_position_width_c-1 downto e_coord_position_width_c);
				local_y_coord	    <= MODULE_ID(e_coord_position_width_c-1 downto 0);
				prev_reset <= RESET;
				in_tx := '0';

			elsif ((PACKET_SENT = '1') or ((RESET = '0') and (prev_reset = '1'))) then
				if ((RESET = '0') and (prev_reset = '1')) then
					seed_1 <= conv_integer(SEED1);
					seed_2 <= conv_integer(SEED2);
					seed1_v := conv_integer(SEED1);
					seed2_v := conv_integer(SEED2);
					packet_tx_counter <= conv_std_logic_vector(e_first_packet_wait_mean_c, inj_wait_max_width_c);
				end if;
				
				in_tx := '0';
				
				if (WORKLOAD > conv_std_logic_vector(0, e_workload_width_c)) then 
					uniform(seed1_v, seed2_v, randNum);
	   	   			wait_time <= calc_wait_time(randNum, WORKLOAD, packet_tx_counter);
	    	  			wait_time_counter_next := conv_std_logic_vector(0,inj_wait_max_width_c);
	     	 			packet_tx_counter <= conv_std_logic_vector(0,inj_wait_max_width_c);
       	       				in_wait_mode <= '1';
        	      				prev_reset <= RESET;
         	     				if (PACKET_SENT = '1') then
          	    					packet_counter_next := packet_counter + conv_std_logic_vector(1, e_packet_counter_width_c);
           	   				else
            	  					packet_counter_next := packet_counter;
             	 				end if;
              					PACKET_REQ <= '0';
              				end if;

	   		elsif (in_wait_mode = '1') then
		   		wait_time_counter_next := wait_time_counter + conv_std_logic_vector(1,inj_wait_max_width_c);
		   		packet_counter_next := packet_counter;
		   	else
		   		wait_time_counter_next := wait_time_counter;
		   		packet_counter_next := packet_counter;
	   		end if; 

	   		if (in_wait_mode = '1') and (wait_time_counter = wait_time) then
	      			-- Randomize SL		      			    
	      			uniform(seed1_v,seed2_v,randNum);  
	      			sl_var := conv_std_logic_vector(calc_uniform(randNum, conv_integer(MAX_SL), 0), msl_ind_width);	   
	                 			SL <= sl_var;           
                  
         				-- Randomize VC  
     				uniform(seed1_v,seed2_v,randNum);         
         				VC <= conv_std_logic_vector(calc_uniform(randNum, conv_integer(MAX_VC), 0), vc_width);	        
         
         				-- Randomize number of flits in packet
         				uniform(seed1_v,seed2_v,randNum);
         				
         				case sl_var is
         					when "11" 	=> PACKET_SIZE <= conv_std_logic_vector(
	                    						calc_uniform(randNum,e_small_size_max_flit_cout_c,e_min_flit_count_c), 
	                    						e_packet_size_width_c);

	                    				when "00" 	=> PACKET_SIZE <= conv_std_logic_vector(
	                    						calc_uniform(randNum,e_max_flit_count_c,e_medium_size_max_flit_cout_c+1), 
	                    						e_packet_size_width_c);
	                    				
	                    				when others	=> PACKET_SIZE <= conv_std_logic_vector(
	                    						calc_uniform(randNum,e_medium_size_max_flit_cout_c,e_small_size_max_flit_cout_c+1), 
	                    						e_packet_size_width_c);
         				end case;
         
         				dest_x_coord := MODULE_ID(2*e_coord_position_width_c-1 downto e_coord_position_width_c);
         				dest_y_coord := MODULE_ID(e_coord_position_width_c-1 downto 0);
         				
         				while (dest_x_coord = MODULE_ID(2*e_coord_position_width_c-1 downto e_coord_position_width_c)) and
         					(dest_y_coord = MODULE_ID(e_coord_position_width_c-1 downto 0)) loop
	         				-- Randomize destination's X coordinate
 	        				uniform(seed1_v,seed2_v,randNum);
  	        				dest_x_coord := conv_std_logic_vector(
	  	                     				calc_uniform(randNum,e_coord_position_width_c), e_coord_position_width_c);
         
    	     				-- Randomize destination's Y coordinate
     	    				uniform(seed1_v,seed2_v,randNum); 
      	    				dest_y_coord := conv_std_logic_vector(
	      	                 				calc_uniform(randNum,e_coord_position_width_c), e_coord_position_width_c);
	                       	end loop;
         
         				in_wait_mode   	<= '0';
         				if (WORKLOAD > conv_std_logic_vector(0, e_workload_width_c)) then
	         				PACKET_REQ		<= '1';
	         				in_tx := '1';
	         			end if;
         
         				SOURCE_ROUTING <=  calc_packet_route(local_x_coord,local_y_coord,dest_x_coord,dest_y_coord);	
            
         				PACKET_ID      <= (local_x_coord & local_y_coord & packet_counter_next);
         
--         				packet_tx_counter <= conv_std_logic_vector(0,inj_wait_max_width_c);
         
      			end if;  
      			
      			seed_1 <= seed1_v;
      			seed_2 <= seed2_v;
      			
      			wait_time_counter <= wait_time_counter_next;
      			packet_counter <= packet_counter_next;
      			
      			if (in_tx = '1') then
      				packet_tx_counter <= packet_tx_counter + conv_std_logic_vector(1,inj_wait_max_width_c);
      			end if;
      			
 		end if;  

	end process;
   
end injector_packet_gen_arch;
